home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 1995 #5 & #6 / Amiga Plus CD - 1995 - No. 5 and 6.iso / pd / serien / purity / nr.12 / workshop / pascalkursii.txt < prev    next >
Text File  |  1995-04-21  |  17KB  |  446 lines

  1.  
  2.   +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  3.   +                 Systemprogrammierung in PCQ-Pascal                  +
  4.   +              Kurs für AMIGAGadget und Purity- Teil II               +
  5.   +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  6.  
  7.   Bisherige Kursteile :
  8.  
  9.     Teil I   : Voraussetzungen,Screens,Windows
  10.  
  11.  
  12.  Und hallo !
  13.  Und hier wären wir zum zweiten Teil dieses tollen Kurses !
  14.  Alle da ? Jaaaa !! Gut. Also, ich muß noch eine Entschuldigung
  15.  anbringen : ähm...stotter...die CloseWork-Routine war ein leichter Schuß
  16.  in den Ofen.... Man sollte erst das Window und dann den Screen
  17.  schließen. Funktioniert hat es aber trotzdem.
  18.  Beim letzten Mal haben wir Screens und Windows behandelt. Wir können
  19.  jetzt also unsern eigenen Bildschirm aufmachen.
  20.  So weit, so gut. Doch was machen wir jetzt mit dem ganzen ?
  21.  Das Zeug liegt leer rum und stört nur. Die Dinger müssen doch zu was
  22.  zu gebrauchen sein. Ein bißchen drin rummalen und Text ausgeben wäre
  23.  gar nicht uninteressant. Deshalb
  24.  
  25.  III. Einfache Grafikausgabe
  26.  
  27.  Bisher sind wir ja ganz gut mit der "Intuition.Library" ausgekommen.
  28.  Das reicht nun aber nicht mehr. Wir brauchen etwas, was uns hilft,
  29.  unsere optischen Vorstellungen zu verwirklichen - die "Graphics.Library".
  30.  Was die Intuition-Library für Screens und Windows ist, ist die
  31.  Graphics-Library für Rastports und Bitmaps. Was,was,was ?? Das war
  32.  zugegebenermaßen gemein von mir - einen neuen Begriff mit zwei anderen
  33.  neuen zu erklären. Ein Rastport ist ein Graphics-Element, das den
  34.  vereinfachten Zugriff auf Bitmaps ermöglicht. Bitmap nennt man die
  35.  Verknüpfung mehrerer Bitplanes (siehe Teil 1 !!). Die Verbindung
  36.  zwischen Graphics und Intuition ist z.B. das Window, das wiederum
  37.  einen vereinfachten Zugriff auf Rastports ermöglicht. Genug der grauen
  38.  Theorie. Wie malen wir jetzt einen Punkt in unser Window ? Ganz einfach :
  39.  
  40.                  WritePixel (window^.RPort,xk,yk)
  41.  
  42.   Man benötigt einen Zeiger auf das Window und übergibt der WritePixel
  43.   -Routine die x- und die y-Koordinate des zu zeichnenden Punktes.
  44.   Fertig.
  45.   Wer jetzt suchend um sich schaut und nicht versteht, was x- und
  46.   y-Koordinaten sind und noch nie so etwas gegessen hat, dem sei
  47.   geholfen. Man kann sich ein Window als Koordinatenkreuz (mal wieder
  48.   in der Schule gepennt ??) vorstellen. Durch so ein Koordinatenkreuz
  49.   lässt sich jeder Punkt einer Fläche als Zahlenpaar beschrieben. Die
  50.   x-Koordinate beschreibt die Entfernung vom linken Rand, die y-Koordinate
  51.   normalerweise vom unteren Rand. Gemeinerweise ist das beim Computer nicht
  52.   so. Der Ursprung (0/0) liegt hier nicht links unten, sondern links
  53.   oben. Aha ! Also zeigt die y-Koordinate den Abstand vom oberen Rand.
  54.   Logisch, oder ? Wenn wir ein Window der Breite 400 aufgemacht haben, dann
  55.   gehen unsere x-Koordinaten von 0 bis 400. Aha ! Feine Sache, oder ?
  56.   Eins sollte man aber beachten : Wenn man x-Werte von 0 oder 1, bzw.
  57.   von 399 oder 400 verwendet, dann würde in so einem Window (400er Breite)
  58.   der Rahmen beschädigt. Also : aufpassen mit dem Rand (auch gerade die
  59.   Titelleiste !!).
  60.   Das wär's dann wohl.
  61.  
  62.   Also legen wir doch gleich mal los ....
  63.  
  64.   HAAAAAAALT !!! Reingefallen ! Wir brauchen noch etwas ganz Wichtiges !
  65.   Wir wollen ja die Graphics-LIBRARY benutzen ! Und was müssen wir machen,
  66.   damit wir sie auch verwenden können ? Richtig - sie muß erstmal aufgemacht
  67.   werden. Da bietet uns das Include-File "Exec/Libraries.I" eine brauchbare
  68.   Routine : OpenLibrary. Sie benötigt den Namen der Library und die
  69.   Versionsnummer, die die Library mindestens haben muß. Als Rückgabewert
  70.   erhalten wir einen Pointer auf eine Library. Was wir nun mit dem machen ?
  71.   Ganz einfach. PCQ erwartet ihn an einer ganz bestimmten Stelle.
  72.   Nämlich in der Variablen "GfxBase", die im File "Graphics/Graphics.I"
  73.   deklariert wird. Als dann, nun können wir wohl beginnen...
  74.   Weit gefehlt ! WritePixel bringt einfach einen Punkt auf den Bildschirm.
  75.   Wir wollen aber einen in der Vordergrundfarbe und nicht etwa einen
  76.   in der Hintergrundfarbe !! Also müssen wir die Zeichenfarbe festlegen :
  77.  
  78.     SetAPen (window^.RPort , farbregister)
  79.  
  80.   Farbregister 0 wäre die Hintergrundfarbe. Wir nehmen also Farbregister 1.
  81.   Aber jetzt geht es los ! Wieder falsch. Schaut man nämlich mal in das
  82.   File "Graphics.I", so sieht man, daß die Befehle hier nicht sind.
  83.   Sie müssen also woanders sein. Gesucht und gefunden im File "Pens.i".
  84.   Und jetzt, ohne lange drumherum zu reden :
  85.  
  86.  
  87.         Program KursProgramm (input , output);
  88.  
  89.         { Listing für den AMIGAGadget/Purity - Pascalkurs ,            }
  90.         { Erste Schritte in der Grafikprogrammierung                   }
  91.  
  92.         {$I "Include:Intuition/Intuition.I" }
  93.         {$I "Include:Exec/Libraries.I"      }
  94.         {$I "Include:Graphics/Graphics.I"   }
  95.         {$I "Include:Libraries/Dos.I"       }
  96.         {$I "Include:Graphics/Pens.I"       }
  97.  
  98.         VAR
  99.                 myscreen : ScreenPtr;
  100.                 mywindow : WindowPtr;
  101.  
  102.  
  103.         PROCEDURE CloseDisplay;
  104.  
  105.         { Sollte ein Teil des Displays offen sein, dann wird er von }
  106.         { dieser Routine geschlossen.                               }
  107.  
  108.         BEGIN
  109.          IF mywindow<>NIL THEN
  110.           CloseWindow (mywindow);
  111.          IF myscreen<>NIL THEN
  112.           CloseScreen (myscreen);
  113.          IF GfxBase<>NIL THEN
  114.           CloseLibrary (GfxBase);
  115.         END;
  116.  
  117.  
  118.         PROCEDURE BreakProgram (reason : STRING);
  119.  
  120.         { Diese Routine schließt alles bisher geöffnete, druckt den }
  121.         { Fehlergrund aus und bricht dann das Programm ab.          }
  122.  
  123.         BEGIN
  124.          CloseDisplay;
  125.          WRITELN ('Program error : ',reason);
  126.          Exit (42);
  127.         END;
  128.  
  129.         PROCEDURE OpenLibs;
  130.  
  131.         CONST   GfxName : String = "graphics.library";
  132.  
  133.         BEGIN
  134.          GfxBase:=OpenLibrary (GfxName,0);
  135.         END;
  136.  
  137.  
  138.         PROCEDURE OpenDisplay;
  139.  
  140.         { Diese Routine erstellt ein Display.                       }
  141.  
  142.         CONST
  143.                 mynewscreen : NewScreen = (0,0,640,256,2,0,1,HIRES,
  144.                                             CUSTOMSCREEN_f,NIL,
  145.                                             "UnserGrafikscreen",NIL,NIL);
  146.  
  147.                 mynewwindow : NewWindow = (0,0,400,200,0,1,0,
  148.                                            SMART_REFRESH+ACTIVATE+
  149.                                            WINDOWDRAG,NIL,NIL,"Unser Grafikwindow",
  150.                                            NIL,NIL,0,0,0,0,CUSTOMSCREEN_f);
  151.  
  152.         BEGIN
  153.           myscreen := OpenScreen (Adr(mynewscreen));
  154.           IF myscreen=NIL THEN BreakProgram ("Couldn't open Screen");
  155.           mynewwindow.Screen:=myscreen;
  156.           mywindow := OpenWindow (Adr(mynewwindow));
  157.           IF mywindow=NIL THEN BreakProgram ("Couldn't open Window");
  158.         END;
  159.  
  160.         PROCEDURE WarteEinWenig;
  161.  
  162.         { Also, das mit den FOR-Schleifen ist mir jetzt doch zu     }
  163.         { unelegant ! Wir binden daher also "libraries/dos.i" ein   }
  164.         { und benutzen nun den Befehl Delay (taktzyklen).           }
  165.  
  166.         BEGIN
  167.           Delay (500);
  168.         END;
  169.  
  170.         PROCEDURE ZeichneEtwas;
  171.  
  172.         VAR ze1 : INTEGER;
  173.  
  174.         BEGIN
  175.          SetAPen (mywindow^.RPort,1);
  176.          FOR ze1:=1 TO 200 DO
  177.           WritePixel (mywindow^.RPort,ze1*2,ze1);
  178.          { zeichnet eine löchrige schräge Linie                     }
  179.         END;
  180.  
  181.         BEGIN
  182.           OpenLibs;
  183.           OpenDisplay;
  184.           ZeichneEtwas;
  185.           WarteEinWenig;
  186.           CloseDisplay;
  187.         END.
  188.  
  189.  Sieht ja schon ganz schnucklig aus. Oder ? Doch es wäre etwas mühsam, wenn
  190.  man nur den Befehl WritePixel hätte, um Grafiken zu erstellen....
  191.  Also gibt es noch ein paar andere wichtige.
  192.  Einen kurzen Überblick über die, die man am häufigsten braucht :
  193.  
  194.  Move (window^.RPort , x , y) - bewegt den Grafikcursor an eine Position
  195.                                 des Rastports, ohne etwas zu zeichnen.
  196.                                 WritePixel bewegt den Grafikcursor zwar
  197.                                 auch, zeichnet aber einen Punkt
  198.  
  199.  Draw (window^.RPort , x , y) - zeichnet eine Linie von der Position des
  200.                                 Grafikcursors zu den neuen Koordinaten
  201.  
  202.  RectFill (window^.RPort ,
  203.           xmin,ymin,xmax,ymax)- zeichnet ein ausgefülltes Rechteck mit den
  204.                                 vier Eckpunkten
  205.                                 E1 (xmin / ymin)
  206.                                 E2 (xmin / ymax)
  207.                                 E3 (xmax / ymax)
  208.                                 E4 (xmax / ymin)
  209.  
  210.  DrawEllipse (window^.RPort,
  211.             cx , cy , a , b)  - zeichnet eine Ellipse mit dem Mittelpunkt
  212.                                 M (cx / cy) und einem maximalen Radius in
  213.                                 x-Ausdehnung von a Pixeln und in
  214.                                 y-Ausdehnung von b Pixeln
  215.  
  216.  DrawCircle (window^.RPort ,
  217.               cx , cy , a )   - Sonderfall von DrawEllipse. X- und y-Radius
  218.                                 sind hier gleich. Aber Achtung : Gerade bei
  219.                                 der sogenannten Med-Res-Auflösung (640*256)
  220.                                 sind das bei weitem keine Kreise mehr !!
  221.  
  222.  ReadPixel (window^.RPort,x,y)- liefert als Rückgabewert das Farbregister
  223.                                 des Bildschirmpunktes an der Stelle P (x/y)
  224.  
  225.  Das sollte für's erste mal reichen. In der nächsten Folge kommen dann
  226.  noch ein paar dazu. Es gibt noch weitaus mehr, die aber für den Einstieg
  227.  zu weit führen und zu umfassende Kenntnisse erfordern, als sie hier in
  228.  den wenigen Zeilen vermittelt werden können.
  229.  
  230.  Was allerdings einen großen Platz einnehmen wird sind selbstgeschriebene
  231.  Prozeduren, die man dann als Grafikbefehle einsetzen kann. So brauchen
  232.  wir ganz dringend einen, um Linien zu ziehen. Sinnigerweise sollten wir
  233.  ihn Line nennen. Eine Linie hat einen Anfangs- und einen Endpunkt.
  234.  Diese müssen übergeben werden. Außerdem natürlich der RastPort.
  235.  Also, jeder mal ran an einen Stift und schnell so eine Prozedur
  236.  entworfen.......
  237.  
  238.  
  239.  
  240.  Fertig ? Gut. Sie sollte etwa so aussehen :
  241.  
  242.  PROCEDURE Line (rp : Address ; xs , ys , xe , ye : Short);
  243.  
  244.  BEGIN
  245.   Move (rp , xs , ys); Draw (rp , xe , ye);
  246.  END;
  247.  
  248.  Einfach, oder ? Und nun gibt es noch eine gewisse Form, die man oft auf
  249.  Computerbildschirmen sieht....ja....ja....genau, das Rechteck. Um
  250.  ausgefüllte Exemplare der Gattung zu bekommen, haben wir ja den
  251.  RectFill-Befehl. Wie zeichnen wir nun aber nur den Rahmen ??
  252.  Eine neue Prozedur muß her !
  253.  
  254.  PROCEDURE Box (rp : Address ; xs , ys , xe , ye : Short);
  255.  
  256.  BEGIN
  257.   Line (rp,xs,ys,xe,ys); Line (rp,xe,ys,xe,ye);
  258.   Line (rp,xe,ye,xs,ye); Line (rp,xs,ye,xs,ys);
  259.  END;
  260.  
  261.  In Sachen Taktzyklen ausnützen sicher nicht das Optimum. Dafür anschaulich
  262.  und kurz.
  263.  
  264.  Nun wollen wir mal kräftig alle unsere Kenntnisse ausspielen. Ein Multi
  265.  -Grafik-Programm ! Vier Fenster, in denen jeweils andere Grafiken
  266.  gezeichnet werden sollen. Also dann : Vorhang auf !
  267.  
  268.         Program KursProgramm (input , output);
  269.  
  270.         { Listing für den AMIGAGadget/Purity - Pascalkurs ,            }
  271.         { Zweite Schritte in der Grafikprogrammierung                  }
  272.  
  273.         {$I "Include:Intuition/Intuition.I" }
  274.         {$I "Include:Exec/Libraries.I"      }
  275.         {$I "Include:Graphics/Graphics.I"   }
  276.         {$I "Include:Libraries/Dos.I"       }
  277.         {$I "Include:Graphics/Pens.I"       }
  278.  
  279.         VAR
  280.                 myscreen : ScreenPtr;
  281.                 mywindow : ARRAY [1..4] OF WindowPtr;
  282.  
  283.  
  284.  
  285.         PROCEDURE Line (rp : Address ; xs , ys , xe , ye : Short);
  286.  
  287.         BEGIN
  288.          Move (rp , xs , ys); Draw (rp , xe , ye);
  289.         END;
  290.  
  291.  
  292.         PROCEDURE Box (rp : Address ; xs , ys , xe , ye : Short);
  293.  
  294.         BEGIN
  295.          Line (rp,xs,ys,xe,ys); Line (rp,xe,ys,xe,ye);
  296.          Line (rp,xe,ye,xs,ye); Line (rp,xs,ye,xs,ys);
  297.         END;
  298.  
  299.  
  300.         PROCEDURE CloseDisplay;
  301.  
  302.         VAR i : Integer;
  303.  
  304.         { Sollte ein Teil des Displays offen sein, dann wird er von }
  305.         { dieser Routine geschlossen.                               }
  306.  
  307.         BEGIN
  308.          FOR i:=1 TO 4 DO
  309.          IF mywindow[i]<>NIL THEN
  310.           CloseWindow (mywindow[i]);
  311.          IF myscreen<>NIL THEN
  312.           CloseScreen (myscreen);
  313.          IF GfxBase<>NIL THEN
  314.           CloseLibrary (GfxBase);
  315.         END;
  316.  
  317.  
  318.         PROCEDURE BreakProgram (reason : STRING);
  319.  
  320.         { Diese Routine schließt alles bisher geöffnete, druckt den }
  321.         { Fehlergrund aus und bricht dann das Programm ab.          }
  322.  
  323.         BEGIN
  324.          CloseDisplay;
  325.          WRITELN ('Program error : ',reason);
  326.          Exit (42);
  327.         END;
  328.  
  329.         PROCEDURE OpenLibs;
  330.  
  331.         CONST   GraphicName : String = "graphics.library";
  332.  
  333.         BEGIN
  334.          GfxBase:=OpenLibrary (GraphicName,0);
  335.         END;
  336.  
  337.  
  338.         PROCEDURE OpenDisplay;
  339.  
  340.         { Diese Routine erstellt ein Display.                       }
  341.  
  342.         CONST
  343.                 mynewscreen : NewScreen = (0,0,640,256,1,0,1,HIRES,
  344.                                             CUSTOMSCREEN_f,NIL,
  345.                                             "Die MultiGrafik-Show !",NIL,NIL);
  346.  
  347.         NewWin1  : NewWindow =  (0,0,320,128,0,1,0,SMART_REFRESH+WINDOWDRAG+
  348.                                 ACTIVATE+SMART_REFRESH,NIL,NIL,"Multi-GFX-Show 1",
  349.                                 NIL,NIL,0,0,0,0,CUSTOMSCREEN_f);
  350.         NewWin2  : NewWindow =  (320,0,320,128,0,1,0,SMART_REFRESH+WINDOWDRAG+
  351.                                 ACTIVATE+SMART_REFRESH,NIL,NIL,"Multi-GFX-Show 2",
  352.                                 NIL,NIL,0,0,0,0,CUSTOMSCREEN_f);
  353.         NewWin3  : NewWindow =  (0,128,320,128,0,1,0,SMART_REFRESH+WINDOWDRAG+
  354.                                 ACTIVATE+SMART_REFRESH,NIL,NIL,"Multi-GFX-Show 3",
  355.                                 NIL,NIL,0,0,0,0,CUSTOMSCREEN_f);
  356.         NewWin4  : NewWindow =  (320,128,320,128,0,1,0,SMART_REFRESH+WINDOWDRAG+
  357.                                 ACTIVATE+SMART_REFRESH,NIL,NIL,"Multi-GFX-Show 4",
  358.                                 NIL,NIL,0,0,0,0,CUSTOMSCREEN_f);
  359.  
  360.  
  361.         BEGIN
  362.           myscreen := OpenScreen (Adr(mynewscreen));
  363.           IF myscreen=NIL THEN BreakProgram ("Couldn't open Screen");
  364.           NewWin1.Screen:=myscreen;
  365.           NewWin2.Screen:=myscreen;
  366.           NewWin3.Screen:=myscreen;
  367.           NewWin4.Screen:=myscreen;
  368.           mywindow[1] := OpenWindow (Adr(NewWin1));
  369.           mywindow[2] := OpenWindow (Adr(NewWin2));
  370.           mywindow[3] := OpenWindow (Adr(NewWin3));
  371.           mywindow[4] := OpenWindow (Adr(NewWin4));
  372.           IF mywindow[4]=NIL THEN BreakProgram ("Couldn't open Window");
  373.         END;
  374.  
  375.         PROCEDURE WarteEinWenig;
  376.  
  377.         BEGIN
  378.           Delay (1000);
  379.         END;
  380.  
  381.         PROCEDURE MultiShow;
  382.  
  383.         VAR ze1 : INTEGER;
  384.             r   : Real;
  385.  
  386.         { Wir durchlaufen eine Schleife, in der für jedes Window ein    }
  387.         { Zeichenbefehl aufgerufen wird.                                }
  388.  
  389.         BEGIN
  390.          FOR ze1:=1 TO 4 DO
  391.           SetAPen (mywindow[ze1]^.RPort,1);
  392.          FOR ze1:=0 TO 50 DO
  393.          BEGIN
  394.           { Zeichenbefehl für Window 1                                  }
  395.           RectFill (mywindow[1]^.RPort,2+(ze1*3),12+(ze1),
  396.                                        2+(ze1*5),24+(ze1*2));
  397.           IF (ze1 / 2)<>(ze1 DIV 2) THEN
  398.           BEGIN
  399.            SetAPen (mywindow[1]^.RPort,0);
  400.            RectFill (mywindow[1]^.RPort,3+(ze1*3),13+(ze1),
  401.                                         1+(ze1*5),23+(ze1*2));
  402.            SetAPen (mywindow[1]^.RPort,1);
  403.           END;
  404.           { Zeichenbefehl für Window 2                                  }
  405.           Line (mywindow[2]^.RPort,10+(6*ze1),20,310-(6*ze1),120);
  406.           Line (mywindow[2]^.RPort,10,20+(ze1*2),310,120-(ze1*2));
  407.           { Zeichenbefehl für Window 3                                  }
  408.           r:=ze1/50*3.141;
  409.           Box(mywindow[3]^.RPort,160+TRUNC(Cos(r)*120),60+TRUNC(Sin(r)*50),
  410.                                  180+TRUNC(Cos(r)*120),70+TRUNC(Sin(r)*50));
  411.           { Zeichenbefehl für Window 4                                  }
  412.           DrawEllipse (mywindow[4]^.RPort,160,64,ze1*3,ze1);
  413.          END;
  414.         END;
  415.  
  416.         BEGIN
  417.           OpenLibs;
  418.           OpenDisplay;
  419.           MultiShow;
  420.           WarteEinWenig;
  421.           CloseDisplay;
  422.         END.
  423.  
  424.  
  425.  
  426.  Boah, oder ???
  427.  Zu dem Programm muß ich noch etwas sagen : ich habe jetzt 3 (!!!!) Stunden
  428.  lang alle möglichen Programmteile umgestellt, immer wieder neu compiliert
  429.  und muß zugeben : ich stehe vor einem Rätsel. Nach dem Compilieren
  430.  läuft das Programm. Wenn ich mit meiner Pascal-Disk neu boote läuft's
  431.  meistens nicht.... Jetzt hab ich mit meiner Systemdisk gebootet und
  432.  es läuft - weiß der Geier, was da nicht richtig ist ! (Schwache Leistung,
  433.  ich geb's ja zu, aber ich hab eigentlich heute noch was anderes vor....)
  434.  Das sollte wohl für diesmal wieder genügen. Probiert schön mit den neuen
  435.  Möglichkeiten und ziert Euch nicht, Fragen, Verbesserungsvorschläge, Lob
  436.  oder sonstwas an die Purity-Macher oder an mich zu schicken.
  437.  
  438.  Andreas Neumann - Auf dem Ruhbühl 151 - W 7997 Immenstaad
  439.  
  440.  Bess dann !
  441.  
  442.          © 28.12.1991 by Andreas Neumann für Gadget Amiga von Nils Kassube
  443.                                          und Purity von Steppenbrand und
  444.                                                         Diesel
  445.  
  446.